package com.ruoyi.system.interceptor;


import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.utils.SpringUtils;
import com.ruoyi.system.domain.SysDataAsset;
import com.ruoyi.system.domain.SysDataLineage;
import com.ruoyi.system.mapper.SysDataLineageMapper;
import com.ruoyi.system.service.ISysDataAssetService;
import com.ruoyi.system.service.ISysDataLineageService;
import com.ruoyi.system.service.impl.SysDataLineageServiceImpl;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.delete.Delete;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.update.Update;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.CompletableFuture;

/**
 * SQL拦截器，用于自动采集数据血缘
 */
@Component
@Intercepts({
        @Signature(type = Executor.class, method = "query",
                args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
        @Signature(type = Executor.class, method = "update",
                args = {MappedStatement.class, Object.class})
})
public class LineageSqlInterceptor3 implements Interceptor {

    private static final List<String> dbname = Arrays.asList("sys_user");
    //@Autowired
    private ISysDataLineageService dataLineageService;
    //private ISysDataLineageService dataLineageService = SpringUtils.getBean(SysDataLineageServiceImpl.class);

    //@Autowired
    private SysDataLineageMapper sysDataLineageMapper;

    //@Autowired
    private ISysDataAssetService sysDataAssetService;
    //@Autowired
    //private SysOperLogMapper operLogMapper;
    //private SysOperLogMapper operLogMapper = SpringUtils.getBean(SysOperLogMapper.class);;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object proceed = invocation.proceed();
        insertDataX(invocation);
        return proceed;
    }

    private void insertDataX(Invocation invocation) {

        CompletableFuture.runAsync(() -> {
            try {
                if (dataLineageService == null) {
                    dataLineageService = SpringUtils.getBean(SysDataLineageServiceImpl.class);
                }
                if (sysDataAssetService == null) {
                    sysDataAssetService = SpringUtils.getBean(ISysDataAssetService.class);
                }
                if (sysDataLineageMapper == null) {
                    sysDataLineageMapper = SpringUtils.getBean(SysDataLineageMapper.class);
                }

                // 获取SQL信息
                MappedStatement ms = (MappedStatement) invocation.getArgs()[0];
                Object parameter = invocation.getArgs()[1];
                BoundSql boundSql = ms.getBoundSql(parameter);
                String sql = boundSql.getSql().trim().toLowerCase();
                //// 忽略简单查询和系统表

                if (!dbname.stream().anyMatch(v -> sql.contains(v))) {
                    return;
                }
                // 解析SQL并提取血缘关系
                SqlCommandType commandType = ms.getSqlCommandType();
                if (
                        Objects.equals(commandType, SqlCommandType.INSERT) ||
                                Objects.equals(commandType, SqlCommandType.DELETE) ||
                                Objects.equals(commandType, SqlCommandType.UPDATE) ||
                                Objects.equals(commandType, SqlCommandType.SELECT)
                ) {
                    Statement statement = CCJSqlParserUtil.parse(sql);
                    SysDataAsset targetAssetObj = new SysDataAsset();
                    List<SysDataAsset> sourceAssetObj = new ArrayList<>();
                    //String targetAsset = null;
                    //List<String> sourceAsset = new ArrayList<>();
                    if (statement instanceof Insert) {
                        /**
                         * 处理INSERT语句（如INSERT INTO B SELECT ... FROM A）
                         */
                        Insert insert = (Insert) statement;
                        //sourceAsset = getTablesFromSelect(insert.getSelect());
                        //if (ObjectUtils.isEmpty(sourceAsset)) {
                        //    sourceAsset = Arrays.asList(getApiMethond());
                        //}
                        //sourceAsset = Arrays.asList(getApiMethond());
                        //targetAsset = insert.getTable().getName();


                        setAsset(targetAssetObj, sourceAssetObj,  insert.getTable().getName());

                    } else if (statement instanceof Delete) {
                        Delete delete = (Delete) statement;
                        //sourceAsset = Arrays.asList( getApiMethond());
                        //targetAsset = delete.getTable().getName();

                        setAsset(targetAssetObj, sourceAssetObj, delete.getTable().getName());
                    } else if (statement instanceof Update) {
                        /**
                         * 处理UPDATE语句         // 简化处理：UPDATE操作视为自身依赖
                         */
                        Update update = (Update) statement;
                        //sourceAsset = Arrays.asList(getApiMethond());
                        //targetAsset = update.getTable().getName();

                        setAsset(targetAssetObj, sourceAssetObj, update.getTable().getName());
                    }
                    //else if (statement instanceof Select) {
                    //    Select select = (Select) statement;
                    //    sourceAsset = getTablesFromSelect(select);
                    //    // 这里简化处理：假设SELECT的下游是当前执行的方法名（实际项目需根据业务场景确定）
                    //    String methodName = getApiMethond();
                    //    targetAsset = "selectMethod:" + methodName;
                    //}

                    //for (String sourceTable : sourceAsset) {
                    //    // 获取或创建资产
                    //    Long sourceAssetId = sysDataAssetService.getOrCreateAsset(sourceTableName, "table", sourceTableName);
                    //    Long targetAssetId = sysDataAssetService.getOrCreateAsset(targetTableName, "table", targetTableName);
                    //
                    //
                    //    SpringUtils.getBean(SysDataLineageServiceImpl.class).saveTableLineage(sourceTable, targetAsset, commandType.name(), null);
                    //}

                    for (SysDataAsset sysDataAsset : sourceAssetObj) {
                        // 获取或创建资产
                        Long sourceAssetId = sysDataAssetService.getOrCreateAsset(sysDataAsset.getAssetName(), sysDataAsset.getAssetType(), sysDataAsset.getAssetDesc());
                        Long targetAssetId = sysDataAssetService.getOrCreateAsset(targetAssetObj.getAssetName(), targetAssetObj.getAssetType(), targetAssetObj.getAssetDesc());

                        SysDataLineage lineage = new SysDataLineage();
                        lineage.setSourceAssetId(sourceAssetId);
                        lineage.setTargetAssetId(targetAssetId);
                        lineage.setRelationType(commandType.name());
                        lineage.setCreateTime(DateUtils.getNowDate());
                        sysDataLineageMapper.insertSysDataLineageSelective(lineage);
                    }
                }
            } catch (Exception e) {
                // 解析失败不影响主流程
                e.printStackTrace();
            }

        });
    }

    private void setAsset(SysDataAsset targetAssetObj, List<SysDataAsset> sourceAssetObj, String targetAsset) {
        for (String assetName : Arrays.asList(getApiMethond())) {
            SysDataAsset sysDataAsset = new SysDataAsset();
            sysDataAsset.setAssetName(assetName);
            sysDataAsset.setAssetType("api");
            sysDataAsset.setAssetDesc(assetName + "接口调用");
            sourceAssetObj.add(sysDataAsset);
        }
        targetAssetObj.setAssetName(targetAsset);
        targetAssetObj.setAssetType("api");
        targetAssetObj.setAssetDesc(targetAsset + "接口调用");
    }

    private String getApiMethond() {
        return "method" + Thread.currentThread().getStackTrace()[3].getMethodName();
    }


    /**
     * 从SELECT语句中提取表名
     */
    private List<String> getTablesFromSelect(Select select) {
        List<String> tables = new ArrayList<>();
        try {
            net.sf.jsqlparser.util.TablesNamesFinder finder = new net.sf.jsqlparser.util.TablesNamesFinder();
            tables = finder.getTableList(select);
        } catch (Exception e) {
            // 忽略解析错误
        }
        return tables;
    }


    /**
     * 驼峰转下划线
     */
    private String camelToUnderline(String name) {
        if (name == null || name.isEmpty()) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        sb.append(Character.toLowerCase(name.charAt(0)));
        for (int i = 1; i < name.length(); i++) {
            char c = name.charAt(i);
            if (Character.isUpperCase(c)) {
                sb.append("_");
                sb.append(Character.toLowerCase(c));
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }


    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        // 可配置属性
    }
}
